package com.lanyou.esb.cook.proxy.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.lanyou.esb.cook.proxy.entity.AccLog;
import com.lanyou.esb.cook.proxy.entity.FieldSystem;
import com.lanyou.esb.cook.proxy.entity.Http;
import com.lanyou.esb.cook.proxy.entity.IfAccTimes;
import com.lanyou.esb.cook.proxy.entity.IfAlrReqTimes;
import com.lanyou.esb.cook.proxy.entity.IfAvgResTimes;
import com.lanyou.esb.cook.proxy.entity.IfReqQuantity;
import com.lanyou.esb.cook.proxy.entity.PfThroughput;
import com.lanyou.esb.cook.proxy.entity.QuantityAnalysis;
import com.lanyou.esb.cook.proxy.entity.Token;
import com.lanyou.esb.cook.proxy.entity.TraceLog;
import com.lanyou.esb.cook.proxy.meta.Environment;
import com.lanyou.esb.cook.proxy.meta.TimeUnit;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.FieldSystemJedisProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.HttpJedisProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.IfAlrReqTimesJedisProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.IfReqQuantityJedisProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.RedisBatchProxy;
import com.lanyou.esb.cook.proxy.redis.proxy.impl.TokenJedisProxy;
import com.lanyou.esb.cook.proxy.redis.vo.Group;
import com.lanyou.esb.cook.proxy.redis.vo.Group.Entry;
import com.lanyou.esb.cook.proxy.service.AccLogService;
import com.lanyou.esb.cook.proxy.service.GroupService;
import com.lanyou.esb.cook.proxy.service.IfAccTimesService;
import com.lanyou.esb.cook.proxy.service.IfAlarmService;
import com.lanyou.esb.cook.proxy.service.IfAlrReqTimesService;
import com.lanyou.esb.cook.proxy.service.IfAvgResTimesService;
import com.lanyou.esb.cook.proxy.service.PfThroughputService;
import com.lanyou.esb.cook.proxy.service.QuantityAnalysisService;
import com.lanyou.esb.cook.proxy.service.RedisBatchService;
import com.lanyou.esb.cook.proxy.service.TraceLogService;
import com.lanyou.esb.cook.proxy.vo.EntityGroup;

/**
 * Redis批处理服务
 * 
 * @author Davey.wu
 */
public class RedisBatchServiceImpl implements RedisBatchService {
	/** Redis批量操作代理 **/
	private RedisBatchProxy redisBatchProxy;
	/** 领域系统Redis操作代理 **/
	private FieldSystemJedisProxy fieldSystemJedisProxy;
	/** Http接口Redis操作代理 **/
	private HttpJedisProxy httpJedisProxy;
	/** 接口令牌Redis操作代理 **/
	private TokenJedisProxy tokenJedisProxy;
	/** 接口请求量控制Redis操作代理 **/
	private IfReqQuantityJedisProxy ifReqQuantityJedisProxy;
	/** 接口已请求次数Redis操作代理 **/
	private IfAlrReqTimesJedisProxy ifAlrReqTimesJedisProxy;

	private IfAlrReqTimesService ifAlrReqTimesService;
	private IfAvgResTimesService ifAvgResTimesService;
	private PfThroughputService pfThroughputService;
	private IfAccTimesService ifAccTimesService;
	private IfAlarmService ifAlarmService;
	private AccLogService accLogService;
	private TraceLogService traceLogService;
	private QuantityAnalysisService quantityAnalysisService;

	@Override
	public void batchPush(Group group) {
		if (group == null) {
			return;
		}
		redisBatchProxy.batchSet(group);
	}
	@Override
	public void batchPushTransaction(Group group) {
		if (group == null) {
			return;
		}
		redisBatchProxy.batchSetTransaction(group);
	}

	@Override
	public void batchPush(IfAlrReqTimes ifAlrReqTimes, IfAccTimes ifAccTimes,
			IfAvgResTimes ifAvgResTimes, PfThroughput pfThroughput,
			AccLog accLog, TraceLog traceLog) {
		// redis批量查询数据条件组合
		Group group = new Group();
		// hash类型条件集合
		group.setHashs(new ArrayList<Entry>(10));
		// string类型条件集合
		group.setStrs(new ArrayList<Entry>(10));
		// set类型条件集合
		group.setSets(new ArrayList<Entry>(10));
		// list类型条件集合
		group.setLists(new ArrayList<Entry>(10));

		//接口在时间区间内已访问次数据组合
		Group tempg = ((GroupService) ifAlrReqTimesService)
				.getGroup(ifAlrReqTimes);
		group = merge(group, tempg);
		// 接口平均响应时间数据组合
		tempg = ((GroupService) ifAvgResTimesService).getGroup(ifAvgResTimes);
		group = merge(group, tempg);
		//平台吞吐量数据组合
		tempg = ((GroupService) pfThroughputService).getGroup(pfThroughput);
		group = merge(group, tempg);
		// 接口访问次数数据组合
		tempg = ((GroupService) ifAccTimesService).getGroup(ifAccTimes);
		group = merge(group, tempg);
		// 访问日志数据组合
		tempg = ((GroupService) accLogService).getGroup(accLog);
		group = merge(group, tempg);
		// 跟踪日志数据组合
		tempg = ((GroupService) traceLogService).getGroup(traceLog);
		group = merge(group, tempg);
		QuantityAnalysis quantityAnalysis = new QuantityAnalysis(
				accLog.getOutEsbDate(), accLog.getReqResult());
		// 流量分析数据组合
		tempg = ((GroupService) quantityAnalysisService)
				.getGroup(quantityAnalysis);
		group = merge(group, tempg);
		try {
			redisBatchProxy.batchSet(group);
		} catch (Exception e) {
			// 提交失败，有些数据需要保存
			ifAvgResTimesService.getPush().putToCollection4Redis(ifAvgResTimes);
			pfThroughputService.getPush().putToCollection4Redis(pfThroughput);
			ifAccTimesService.getPush().putToCollection4Redis(ifAccTimes);
			accLogService.getPush().putToCollection4Redis(accLog);
		}
	}

	/**
	 * 合并
	 * 
	 * @param group
	 * @param tempg
	 * @return
	 */
	private Group merge(Group group, Group tempg) {
		if (tempg == null) {
			return group;
		}
		if (tempg.getHashs() != null) {
			group.getHashs().addAll(tempg.getHashs());
		}
		if (tempg.getStrs() != null) {
			group.getStrs().addAll(tempg.getStrs());
		}
		if (tempg.getSets() != null) {
			group.getSets().addAll(tempg.getSets());
		}
		if (tempg.getLists() != null) {
			group.getLists().addAll(tempg.getLists());
		}
		return group;
	}

	@Override
	public EntityGroup batchGet(String systemCode, String callSystemCode,
			String ifCode, String ifId, String ifVersion, TimeUnit unit,
			Date date, Environment environment) throws Exception {
		// redis批量查询数据条件组合
		Group group = new Group();
		// hash类型条件集合
		List<Entry> hashs = new ArrayList<>();
		// string类型条件集合
		List<Entry> strs = new ArrayList<>();
		group.setHashs(hashs);
		group.setStrs(strs);
		// 调用方系统
		Entry entry = new Entry();
		entry.setKey(fieldSystemJedisProxy.getKey());
		entry.setField(fieldSystemJedisProxy.getKey(callSystemCode));
		entry.setClasses(FieldSystem.class);
		entry.setConvert(true);
		hashs.add(entry);

		// 令牌
		entry = new Entry();
		// 令牌HASH键
		if (Environment.PRODUCTION == environment) {
			entry.setKey(tokenJedisProxy.getKey());
		} else {
			entry.setKey(TokenJedisProxy.HASH_KEY_FOR_TEST_TOKEN);
		}
		entry.setField(tokenJedisProxy.getKeyFromFields(systemCode, ifCode,
				ifVersion, callSystemCode));
		entry.setClasses(Token.class);
		entry.setConvert(true);
		hashs.add(entry);

		// 接口请求量控制
		entry = new Entry();
		entry.setKey(ifReqQuantityJedisProxy.getKey());
		entry.setField(ifReqQuantityJedisProxy
				.getKeyFromFields(ifId, unit.ValueCode));
		entry.setClasses(IfReqQuantity.class);
		entry.setConvert(true);
		hashs.add(entry);

		// 接口已访问次数
		String section = IfAlrReqTimesServiceImpl.getSection(unit, date);
		entry = new Entry();
		entry.setKey(ifAlrReqTimesJedisProxy.getKeyFromFields(ifId, unit.ValueCode,
				callSystemCode, section));
		entry.setClasses(IfAlrReqTimes.class);
		// 接口已请求次数不需要转换
		entry.setConvert(false);
		strs.add(entry);

		// 查询结果映射集合
		Map<Class, Object> map = null;
		// 查询结果
		EntityGroup result = new EntityGroup();
		try {
			map = redisBatchProxy.batchGet(group);
			// 设置调用方系统
			result.setCallSystem((FieldSystem) map.get(FieldSystem.class));
			// 设置令牌
			result.setToken((Token) map.get(Token.class));
			// 设置接口请求量控制
			result.setIfReqQuantity((IfReqQuantity) map
					.get(IfReqQuantity.class));
			// 设置时间区域内接口已请求次数start=========================
			String value = (String) map.get(IfAlrReqTimes.class);
			int times = 0;
			try {
				times = Integer.parseInt(value);
			} catch (Exception e) {
				times = 0;
			}
			IfAlrReqTimes reqTimes = new IfAlrReqTimes();
			reqTimes.setIfId(ifId);
			reqTimes.setCallSystemCode(callSystemCode);
			reqTimes.setSection(section);
			reqTimes.setUnit(unit);
			reqTimes.setTimes(times);
			result.setIfAlrReqTimes(reqTimes);
			// 设置时间区域内接口已请求次数end=========================
		} catch (Exception e) {
			throw e;
		}
		return result;
	}

	@Override
	public EntityGroup getPubSystemAndHttp(String systemCode, String ifCode,
			String ifVersion) throws Exception {
		// redis批量查询数据条件组合
		Group group = new Group();
		// hash类型条件集合
		List<Entry> hashs = new ArrayList<>();
		group.setHashs(hashs);
		// 调用方系统
		Entry entry = new Entry();
		entry.setKey(fieldSystemJedisProxy.getKey());
		entry.setField(httpJedisProxy.getKey(systemCode));
		entry.setClasses(FieldSystem.class);
		entry.setConvert(true);
		hashs.add(entry);

		// HTTP接口
		entry = new Entry();
		entry.setKey(httpJedisProxy.getKey());
		entry.setField(httpJedisProxy
				.getKeyFromFields(systemCode, ifCode, ifVersion));
		entry.setClasses(Http.class);
		entry.setConvert(true);
		hashs.add(entry);

		// 查询结果映射集合
		Map<Class, Object> map = null;
		// 查询结果
		EntityGroup result = new EntityGroup();
		try {
			map = redisBatchProxy.batchGet(group);
			// 设置发布方系统
			result.setPubSystem((FieldSystem) map.get(FieldSystem.class));
			// 设置HTTP接口
			result.setHttp((Http) map.get(Http.class));
		} catch (Exception e) {
			throw e;
		}
		return result;
	}

	public RedisBatchProxy getRedisBatchProxy() {
		return redisBatchProxy;
	}

	public void setRedisBatchProxy(RedisBatchProxy redisBatchProxy) {
		this.redisBatchProxy = redisBatchProxy;
	}

	public FieldSystemJedisProxy getFieldSystemJedisProxy() {
		return fieldSystemJedisProxy;
	}

	public void setFieldSystemJedisProxy(
			FieldSystemJedisProxy fieldSystemJedisProxy) {
		this.fieldSystemJedisProxy = fieldSystemJedisProxy;
	}

	public HttpJedisProxy getHttpJedisProxy() {
		return httpJedisProxy;
	}

	public void setHttpJedisProxy(HttpJedisProxy httpJedisProxy) {
		this.httpJedisProxy = httpJedisProxy;
	}

	public IfReqQuantityJedisProxy getIfReqQuantityJedisProxy() {
		return ifReqQuantityJedisProxy;
	}

	public void setIfReqQuantityJedisProxy(
			IfReqQuantityJedisProxy ifReqQuantityJedisProxy) {
		this.ifReqQuantityJedisProxy = ifReqQuantityJedisProxy;
	}

	public IfAlrReqTimesJedisProxy getIfAlrReqTimesJedisProxy() {
		return ifAlrReqTimesJedisProxy;
	}

	public void setIfAlrReqTimesJedisProxy(
			IfAlrReqTimesJedisProxy ifAlrReqTimesJedisProxy) {
		this.ifAlrReqTimesJedisProxy = ifAlrReqTimesJedisProxy;
	}

	public TokenJedisProxy getTokenJedisProxy() {
		return tokenJedisProxy;
	}

	public void setTokenJedisProxy(TokenJedisProxy tokenJedisProxy) {
		this.tokenJedisProxy = tokenJedisProxy;
	}

	public IfAlrReqTimesService getIfAlrReqTimesService() {
		return ifAlrReqTimesService;
	}

	public void setIfAlrReqTimesService(
			IfAlrReqTimesService ifAlrReqTimesService) {
		this.ifAlrReqTimesService = ifAlrReqTimesService;
	}

	public IfAvgResTimesService getIfAvgResTimesService() {
		return ifAvgResTimesService;
	}

	public void setIfAvgResTimesService(
			IfAvgResTimesService ifAvgResTimesService) {
		this.ifAvgResTimesService = ifAvgResTimesService;
	}

	public PfThroughputService getPfThroughputService() {
		return pfThroughputService;
	}

	public void setPfThroughputService(PfThroughputService pfThroughputService) {
		this.pfThroughputService = pfThroughputService;
	}

	public IfAccTimesService getIfAccTimesService() {
		return ifAccTimesService;
	}

	public void setIfAccTimesService(IfAccTimesService ifAccTimesService) {
		this.ifAccTimesService = ifAccTimesService;
	}

	public IfAlarmService getIfAlarmService() {
		return ifAlarmService;
	}

	public void setIfAlarmService(IfAlarmService ifAlarmService) {
		this.ifAlarmService = ifAlarmService;
	}

	public AccLogService getAccLogService() {
		return accLogService;
	}

	public void setAccLogService(AccLogService accLogService) {
		this.accLogService = accLogService;
	}

	public TraceLogService getTraceLogService() {
		return traceLogService;
	}

	public void setTraceLogService(TraceLogService traceLogService) {
		this.traceLogService = traceLogService;
	}

	public QuantityAnalysisService getQuantityAnalysisService() {
		return quantityAnalysisService;
	}

	public void setQuantityAnalysisService(
			QuantityAnalysisService quantityAnalysisService) {
		this.quantityAnalysisService = quantityAnalysisService;
	}

}
